package base.loader
{
	import flash.events.EventDispatcher;
	import flash.events.NetStatusEvent;
	import flash.net.SharedObject;
	import flash.net.SharedObjectFlushStatus;
	import flash.utils.ByteArray;
	
	import utils.StringUtil;
	
	/**
	 *加载缓存处理类 
	 * @author devin
	 * 
	 */	
	public class LoaderShared extends EventDispatcher
	{
		private static const READ_ERROR_ID:int = 2030;
		/**
		 *系统文件缓存编号 
		 */		
		private var _systemVersion:int;
		/**
		 *对外的文件缓存编号，值意义：-1为当前不可未启用缓存;0=当前不需要更新原有的缓存;>0=当前的缓存号
		 */
		private var _sharedVersion:int=0;
		
		/**
		 *待保存的文件集合 
		 */		
		private var _saveFiles:Array;
		
		/**
		 *是否有过改变 
		 */		
		private var _changed:Boolean;
		
		/**
		 *用来保存配置及记录缓存文件状态的SharedObject
		 */		
		private var _cofigSO:SharedObject;
		/**
		 *当前是否支持保存缓存 
		 */		
		private var _isCache:Boolean=false;

		/**
		 *当前是否支持保存缓存 
		 */
		public function set isCache(value:Boolean):void
		{
			if(_isCache == value)return;
			_isCache = value;
			if(_isCache)dispatchEvent(new LoaderEvent(LoaderEvent.SHARED_OBJECT_CACHE_OPEN));
		}

		/**
		 *当前是否支持保存缓存 
		 */
		public function get isCache():Boolean
		{
			return _isCache;
		}

		/**
		 *系统版本号是否更新过 
		 */		
		private var _systemVersionIsUp:Boolean;

		/**
		 *系统版本号是否更新过 
		 */
		public function get systemVersionIsUp():Boolean
		{
			return _systemVersionIsUp;
		}

		/**
		 * @private
		 */
		public function set systemVersionIsUp(value:Boolean):void
		{
			_systemVersionIsUp = value;
		}

		private var _root:String;
		
		public function LoaderShared()
		{
		}
		
		private static var _instance:LoaderShared;
		public static function get Instance() : LoaderShared
		{
			if(_instance == null)
			{
				_instance = new LoaderShared();
			}
			return _instance;
		}
		
		/**
		 *注册类 
		 * 
		 */		
		public function register():void
		{
			_changed=false;
			_saveFiles=new Array();
			loadCacheConfig();
		}
		
		/**
		 *加载缓存基本配置数据
		 * 
		 */		
		private function loadCacheConfig():void
		{
			try
			{
				_cofigSO = SharedObject.getLocal("cacheCofig");//取得缓存的配置文件(里面记录了基本信息、缓存文件清单)
				_cofigSO.addEventListener(NetStatusEvent.NET_STATUS, __onNetStatus);
				_systemVersion = int(_cofigSO.data["data"]["systemVersion"]);//取得当前系统缓存文件编号
				if(_systemVersion>0)
				{//如果取到了版本号，说明上次是有保存版本的缓存的，则说明当前是支持缓存的
					isCache=true;
				}
			}
			catch(e:Error)
			{
				if(e.errorID == READ_ERROR_ID)
				{
					resetErrorVersion();
				}
				_sharedVersion=-1;
			}
		}
		
		/**
		 *缓存文件 
		 * @param path 要缓存的文件源路径
		 * @param data 要缓存的文件源数据
		 * 
		 */		
		public function cacheFile(path:String,dataByte:ByteArray):void
		{
			if(!_isCache || StringUtil.isEmpty(path) || dataByte==null || dataByte.length<=0)return;
			var saveData:ByteArray=new ByteArray();
			saveData.writeBytes(dataByte);
			_saveFiles.push({path: getPath(path),data:saveData});
			_changed = true;
			saveCacheFiles();
		}
		
		/**
		 *根据文件路径取得缓存文件对象 
		 * @param path 文件路径
		 * @return 
		 * 
		 */		
		public function getCachedFile(path:String):ByteArray
		{
			var p:String = getPath(path);
			var file:ByteArray = getCacheFileBySaveFiles(p);//从将要保存至缓存中取文件，看是否存在，如果存在就不需要去缓存中取
			if(file == null && _cofigSO.data["data"]!=null && _cofigSO.data["data"][p])
			{//如果文件对象为空且从缓存配置中取得该路径存在对应的缓存文件
				try
				{
					var so:SharedObject = SharedObject.getLocal(p);
					file = ByteArray(so.data["data"]);
				}
				catch(e:Error)
				{
					file=null;
				}
			}
//			if(file)
//			{
//				var byteFile:ByteArray=new ByteArray();
//				byteFile.writeBytes(file);
//				file=null;
//				return byteFile;
//			}
			return file;
		}
		
		/**
		 *检查是否存在指定的缓存文件 
		 * @param path 文件路径
		 * @return 
		 * 
		 */		
		public function hasCachedFile(path:String):Boolean
		{
			var p:String = getPath(path);
			var isExist:Boolean=false;
			for each(var cacheObject:Object in _saveFiles)
			{
				if(cacheObject.path == p)
				{
					isExist=true;
					break;
				}
			}
			
			if(!isExist && _cofigSO.data["data"]!=null && _cofigSO.data["data"][p])
			{
				isExist=true;
			}
			return isExist;
		}
		
		/**
		 *根据文件路径从将要保存至缓存中的对象列表中取得文件 
		 * @param path 路径
		 * 
		 */		
		private function getCacheFileBySaveFiles(path:String):ByteArray
		{
			for each(var cacheObject:Object in _saveFiles)
			{
				if(cacheObject.path == path) return ByteArray(cacheObject.data);
			}
			
			return null;
		}
		
		/**
		 *检查并设置本地缓存开启状态 
		 * 
		 */		
		public function setSharedObjectState():void
		{
			try
			{
				if(_cofigSO.data["data"])
				{
					var state:String = _cofigSO.flush(150 * 1024 * 1024);
					if(state==SharedObjectFlushStatus.PENDING)
					{
						dispatchEvent(new LoaderEvent(LoaderEvent.SHARED_OBJECT_SAVE_ALERT));
					}
					else
					{
						isCache=true;
						_changed=true;
						if(_cofigSO)
						{
							_cofigSO.removeEventListener(NetStatusEvent.NET_STATUS, __onNetStatus);
						}
						saveCacheFiles();
					}
				}
			}
			catch(e:Error){}
		}
		
		/**
		 *执行保存缓存文件 
		 * 
		 */		
		private function saveCacheFiles():void
		{
			try
			{
				if(_cofigSO.data["data"] && _changed && _isCache)
				{
					saveFileItem();
					if(_saveFiles.length == 0)_changed = false;
					_sharedVersion=_systemVersion;
				}
			}
			catch(e:Error){}
		}
		
		/**
		 *保存列表中的单项缓存文件 
		 * 
		 */		
		private function saveFileItem():void
		{
			if(!_saveFiles || _saveFiles.length<=0)
			{
				return;
			}
			var obj:Object = _saveFiles.shift();
			var so:SharedObject = SharedObject.getLocal(obj.path);
			so.data["data"] = obj.data;
			so.flush();
			so=null;
			_cofigSO.data["data"][obj.path] = true;
			_cofigSO.flush();
			obj.data=null;
			obj=null;
			saveFileItem();
		}
		
		/**
		 * 更新模块配置,支持*的通配符
		 * @param config
		 *  <version from="versionid" to="vid">
		 * 		<file value="*" /> 指所有的文件。
		 *  	<file value="xx.swf or 目录名/xx.swf" /> 指指定路径的文件。
		 * 		<file value="目录名/*.*" /> 指指定目录名下的所有文件，包括子孙级。
		 * 		<file value="目录名/*.swf" /> 指仅仅只是指定目录名下的*.swf文件，不包括子孙级。
		 *  </version>
		 * 
		 */		
		public function parseUpdate(config:XML):void
		{
			try
			{
				_root=String(config.@root);
				var vs:XMLList = config.version;
				for each(var node:XML in vs)
				{
					var fromv:int = int(node.@from);
					var tov:int = int(node.@to);
					var fs:XMLList = node.file;
					var updatelist:Array = new Array();
					if(tov <= fromv) continue;//如果至x缓存编号小于等于从x缓存编号，则返回，表示不需要更新
					if(_systemVersion >=tov)continue;//如果当前系统的缓存版本大于等于配置中的版本号，则跳过
					
					for each(var fn:XML in fs)
					{
						updatelist.push(_root+String(fn.@value))
					}
					updateCacheFiles(fromv,tov,updatelist);
				}
			}
			catch(e:Error)
			{
				//更新失败，清除所有的缓存
				_systemVersion = -1;
				_changed = true;
			}
			saveCacheFiles();
		}
		
		/**
		 *更新缓存 
		 * @param fromVer 从x缓存编号
		 * @param toVer 至x缓存编号
		 * @param updatelist 更新文件路径列表
		 */
		private function updateCacheFiles(fromVer:int,toVer:int,updateList:Array):void
		{
			if(_systemVersion < toVer)
			{//如果当前缓存编号小于至要更新至的缓存编号
				if(_systemVersion < fromVer)
				{
					//当前版本太旧，清除所有系统缓存
					_cofigSO.data["data"] = new Object();
				}
				else
				{
					clearCacheFile(updateList);
				}
				_systemVersion = toVer;//设置当前系统缓存文件的版本编号
				_cofigSO.data["data"]["systemVersion"] = toVer;//在缓存配置清单中设置系统缓存文件的版本编号
				_changed = true;
				_systemVersionIsUp=true;
			}
		}
		
		/**
		 *将指定的列表中的文件路径对应的缓存文件从缓存存配置中进行删除 
		 * @param updateList 要更新的文件列表
		 * 
		 */		
		private function clearCacheFile(updateList:Array):void
		{
			var updated:Array = new Array();
			for each(var path:String in updateList)
			{
				var p:String = getPath(path);
				p = p.replace("*","\\w*");
				updated.push(new RegExp("^"+p));
			}
			
			var temp:Array = new Array();
			for(var f:String in _cofigSO.data.data)
			{
				if(hasUpdate(f,updated))
				{
					temp.push(f);
				}
			}
			
			for each(var n:String in temp)
			{
				delete _cofigSO.data["data"][n];//从缓存配置清单中删除掉要更新的缓存文件(这样就达到了要取这个缓存文件时，找不到对象，就会重新去外部加载)
			}
		}
		
		//		private static function clearFiles(filter:String):void
		//		{
		//			if(_cacheCofig)
		//			{
		//				var updated:Array = new Array();
		//				var t:String = getPath(filter);
		//				t = t.replace("*","\\w*");
		//				updated.push(new RegExp("^"+t));
		//				
		//				var temp:Array = new Array();
		//				for(var f:String in _cacheCofig)
		//				{
		//					if(hasUpdate(f,updated))
		//					{
		//						temp.push(f);
		//					}
		//				}
		//				
		//				for each(var n:String in temp)
		//				{
		//					trace("clear cache:",n);
		//					delete _cacheCofig[n];
		//				}
		//				
		//				try
		//				{
		//					if(_isCache)
		//					{
		//						_cofigSO.flush(20 * 1024 * 1024);
		//					}
		//				}
		//				catch(e:Error){}
		//			}
		//		}
		
		private function hasUpdate(path:String,updateList:Array):Boolean
		{
			for each(var s:RegExp in updateList)
			{
				if(path.match(s))
				{
					return true;
				}
			}
			return false;
		}
		
		public var ReadShareError:Boolean = false;
		public function resetErrorVersion():void
		{
			_systemVersion=Math.random()*-999999;
			ReadShareError = true;
		}
		
		public function clearAll():void
		{
			_cofigSO.clear()
		}
		
		private var _retryCount:int = 0;
		private function __onNetStatus(event:NetStatusEvent):void
		{
			switch (event.info.code) 
			{
				case "SharedObject.Flush.Failed":
					//第一次用户同意时，会保存失败，重试2次还失败，放弃
					if(_retryCount < 1)
					{
						try
						{
							_cofigSO.flush(150 * 1024 * 1024);
						}
						catch(e:Error){}
						_retryCount ++;
					}
					else
					{
						_isCache = false;
						_sharedVersion=-1;
						dispatchEvent(new LoaderEvent(LoaderEvent.SHARED_OBJECT_SAVE_FAILED));
					}
					break;
				case "SharedObject.Flush.Success":
//					if(!_isCache)
//					{
						dispatchEvent(new LoaderEvent(LoaderEvent.SHARED_OBJECT_SAVE_SUCCESS));
						_isCache = true;
						if(_cofigSO)
						{
							_cofigSO.removeEventListener(NetStatusEvent.NET_STATUS, __onNetStatus);
						}
//					}
					saveFileItem();
					break;
				default:
					_retryCount = 0;
					break;
			}
		}
		
		/**
		 * 替换掉http://..../ 
		 */		
		private static const _reg1:RegExp = /http:\/\/[\w|.|:]+\//i;
		/**
		 * 替换: . / 
		 */		
		private static const _reg2:RegExp = /[:|.|\/]/g;
		public function getPath(path:String):String
		{
			//只取问号前面部分
			var index:int = path.indexOf("?");
			if(index != -1)
			{
				path = path.substring(0,index)
			}
			path = path.replace(_reg1,"");
			return path.replace(_reg2,"-");
		}
		
		/**
		 *系统文件缓存编号 
		 */
		public function get systemVersion():int
		{
			return _systemVersion;
		}
		
		/**
		 *对外的文件缓存编号，值意义：-1为当前不可未启用缓存;0=当前不需要更新原有的缓存;>0=当前的缓存号
		 */
		public function get sharedVersion():int
		{
			return _sharedVersion;
		}
	}
}